package io.scnb.lesson001.demo17;

import org.junit.Test;
import org.springframework.cglib.proxy.*;

import java.lang.reflect.Method;

public class CglibTest {

    @Test
    public void test1() {
        // 使用Enhancer给某个类创建代理类
        // 1. 创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 2. 通过setSuperclass来设置父类型，即需要给哪个类创建代理类
        enhancer.setSuperclass(Service1.class);
        // 3. 设置回调 当调用代理对象的任何方法时，都会被MethodInterceptor接口的invoke方法处理
        // MethodInterceptor接口实现了org.springframework.cglib.proxy.Callback接口
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("调用方法：" + method);
                // 调用被代理类的方法
                Object result = methodProxy.invokeSuper(o, objects);
                return result;
            }
        });
        // 4. 获取代理类对象，调用enhancer.create方法获取代理对象
        Service1 proxy = (Service1) enhancer.create();
        proxy.m1();
        proxy.m2();
    }

    @Test
    public void test2() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Service2.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("调用方法：" + method);
                Object result = methodProxy.invokeSuper(o, objects);
                return result;
            }
        });
        Service2 proxy = (Service2) enhancer.create();
        // 在m1中调用m2方法，也被代理类拦截了
        proxy.m1();
        proxy.m2();
    }

    @Test
    public void test3() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Service3.class);
        // 通过FixedValue接口，让被代理类的所有方法都返回一个固定的值
        enhancer.setCallback(new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return "scnb";
            }
        });

        Service3 proxy = (Service3) enhancer.create();
        System.out.println(proxy.m1());
        System.out.println(proxy.m2());
        System.out.println(proxy.toString());
    }

    @Test
    public void test4() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Service4.class);
        Callback[] callbacks = {
            new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    long start = System.nanoTime();
                    Object result = methodProxy.invokeSuper(o, objects);
                    long end = System.nanoTime();
                    System.out.println(method + "耗时（纳秒）:" + (end-start));
                    return result;
                }
            },
            new FixedValue() {
                @Override
                public Object loadObject() throws Exception {
                    return "scnb";
                }
            }
        };

        enhancer.setCallbacks(callbacks);
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                String methodName = method.getName();
                if (methodName.startsWith("insert")) {
                    return 0;
                } else {
                    return 1;
                }
            }
        });

        Service4 proxy = (Service4) enhancer.create();
        System.out.println("---------------");
        proxy.insert1();
        System.out.println("---------------");
        proxy.insert2();
        System.out.println("---------------");
        System.out.println(proxy.get1());
        System.out.println("---------------");
        System.out.println(proxy.get2());
    }

    @Test
    public void test5() {
        Enhancer enhancer = new Enhancer();
        // 创建2个callback
        Callback costTimeCallback = (MethodInterceptor) (Object o, Method method, Object[] objects, MethodProxy methodProxy) -> {
            long start = System.nanoTime();
            Object result = methodProxy.invokeSuper(o, objects);
            long end = System.nanoTime();
            System.out.println(method + ", 耗时(纳秒):" + (end - start));
            return result;
        };
        // 拦截所有get开头的方法，返回固定值
        Callback fixedValueCallback = (FixedValue) () -> "scnb";

        CallbackHelper callbackHelper = new CallbackHelper(Service4.class, null) {
            @Override
            protected Object getCallback(Method method) {
                return method.getName().startsWith("insert") ? costTimeCallback : fixedValueCallback;
            }
        };

        enhancer.setSuperclass(Service4.class);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        enhancer.setCallbackFilter(callbackHelper);

        Service4 proxy = (Service4) enhancer.create();
        System.out.println("---------------");
        proxy.insert1();
        System.out.println("---------------");
        proxy.insert2();
        System.out.println("---------------");
        System.out.println(proxy.get1());
        System.out.println("---------------");
        System.out.println(proxy.get2());

    }

    @Test
    public void test6() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Service3.class);
        // 直接放行，不做任何操作
        enhancer.setCallback(NoOp.INSTANCE);
        Service3 proxy = (Service3) enhancer.create();
        // 被调用的方法没有被代理做任何处理
        System.out.println(proxy.m1());
        System.out.println(proxy.m2());
    }

    @Test
    public void test7() {
        // 创建service1代理
        Service1 service1 = CostTimeProxy.createProxy(new Service1());
        service1.m1();

        // 创建service3代理
        Service3 service3 = CostTimeProxy.createProxy(new Service3());
        service3.m1();
    }
}
